package org.dreamwork.jasmine2.parser;

import org.dreamwork.text.TextParser;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by IntelliJ IDEA.
 * User: seth
 * Date: 2009-2-3
 * Time: 13:57:57
 */
public class JavaCodeSnipParser extends TextParser {
    private Pattern pattern = Pattern.compile ("void|([a-zA-Z_$][a-zA-Z0-9_S]*)[\\s]+([a-zA-Z_$][a-zA-Z0-9_S]*)[\\s]*\\((([\\w]+[\\s]+[\\w]+),?)?\\)[\\s]*\\{", Pattern.MULTILINE);
    private Pattern classPattern = Pattern.compile ("^([\\s]*class|(.*)[\\s]+)class[\\s]+(.*)[\\s]*\\{", Pattern.MULTILINE);
    private Pattern forPattern = Pattern.compile ("[\\W]*for[\\s]*\\(", Pattern.MULTILINE);
    private Pattern p_variable = Pattern.compile ("^\\s*((private|protected|public)\\s+)?[\\w$.]+\\s+[\\w$]+\\s*=\\s*.*;", Pattern.MULTILINE);

    private List<String> classes = new ArrayList<String> (), functions = new ArrayList<String> ();
    private List<String> stmts = new ArrayList<String> ();
    private List<String> variables = new ArrayList<String> ();

    private static final Logger logger = Logger.getLogger (JavaCodeSnipParser.class);

    public JavaCodeSnipParser (String code) {
        super (code);
    }

    public void parse () {
        StringBuffer sb = new StringBuffer ();
        StringBuffer line = new StringBuffer ();

        boolean inFunction = false, inClass = false;
        int classMatch = 0, functionMatch = 0;
//        VirtualClass vc = new VirtualClass ();
        for (int c = nextChar (); c != -1; c = nextChar ()) {
            sb.append ((char) c);
            line.append ((char) c);
            switch (c) {
                case ';':
                    if (!inClass && !inFunction) {
                        String s = line.toString ();

                        Matcher m = p_variable.matcher (s);
                        if (m.matches ()) {
                            variables.add (s);
                            line.setLength (0);
                        } else {
                            m = forPattern.matcher (s);
                            if (!m.lookingAt ()) {
                                stmts.add (line.toString ());
                                line.setLength (0);
                            }
                        }
                    }
                    break;
                case '{':
                    String s = sb.toString ();
                    Matcher matcher = classPattern.matcher (s);
                    if (matcher.find ()) {
                        inClass = true;
                        classMatch++;
                        functionMatch = 0;
                        sb.setLength (0);
                    } else if (inClass) {
                        classMatch++;
                    } else if (inFunction) {
                        functionMatch++;
                    } else {
                        Matcher forMatcher = forPattern.matcher (line);
                        boolean isFor = forMatcher.lookingAt ();

                        matcher = pattern.matcher (s);
                        boolean isFunction = matcher.find ();

                        if (isFunction && !isFor) {
                            inFunction = true;
                            functionMatch++;
                            sb.setLength (0);
                        }
                    }
                    break;
                case '}':
                    if (inClass) {
                        classMatch--;
                        if (classMatch == 0) {
                            classes.add (line.toString ());
                            line.setLength (0);
                            inClass = false;
                        }
                    } else if (inFunction) {
                        functionMatch--;
                        if (functionMatch == 0) {
                            functions.add (line.toString ());
                            line.setLength (0);
                            inFunction = false;
                        }
                    } else {
                        stmts.add (line.toString ());
                        line.setLength (0);
                    }
                    break;
            }
        }

        logger.debug ("=========================== classes ====================================");
        for (int i = 0; i < classes.size (); i++) {
            logger.debug (i + "\t" + classes.get (i));
            logger.debug ("--------------------------------------------------------------------");
        }

        logger.debug ("=========================== functions ====================================");
        for (int i = 0; i < functions.size (); i++) {
            logger.debug (i + "\tfunction\t" + functions.get (i).trim ());
            logger.debug ("--------------------------------------------------------------------");
        }

        logger.debug ("=========================== statements ====================================");
        for (int i = 0; i < stmts.size (); i++) {
            logger.debug (i + "\tStatement\t" + stmts.get (i).trim ());
            logger.debug ("--------------------------------------------------------------------");
        }

        logger.debug ("=========================== varialbes ====================================");
        for (int i = 0; i < variables.size (); i++) {
            logger.debug (i + "\tVariable\t" + variables.get (i).trim ());
            logger.debug ("--------------------------------------------------------------------");
        }
    }

    public List<String> getClasses () {
        return classes;
    }

    public List<String> getFunctions () {
        return functions;
    }

    public List<String> getStatements () {
        return stmts;
    }

    public List<String> getVariables () {
        return variables;
    }

/*
    public static void main (String[] args) throws Exception {
        String code = "out.println (\"Hello Jasmine\");\n" +
                "\n" +
                "private static class VirtualConstruction extends VirtualMethod {\n" +
                "    public String getReturnType () {\n" +
                "        for (int i = 0; i < 100; i ++) {\n" +
                "            System.out.println (i);\n" +
                "        }\n" +
                "        return \"\";\n" +
                "    }\n" +
                "\n" +
                "    public void setReturnType (String returnType) {\n" +
                "        super.setReturnType (\"\");\n" +
                "    }\n" +
                "}\n" +
                "\n" +
                "private void doSomething () {\n" +
                "\tSystem.out.println (\"I'm doing something...\");\n" +
                "}\n" +
                "\n" +
                "private static class XX \n" +
                "{\n" +
                "\tprivate name;\n" +
                "\tpublic void setName (String name) {\n" +
                "\t\tthis.name = name;\n" +
                "\t}\n" +
                "\t\n" +
                "\tpublic String getName () {\n" +
                "\t\treturn name;\n" +
                "\t}\n" +
                "}\n" +
                "\n" +
                "int a = 0;\n" +
                "for (int i = 10; i >= a; i ++) {\n" +
                "\tdoSomething ();\n" +
                "}\n" +
                "\n" +
                "public int getNumber () {\n" +
                "\treturn \n" +
                "\t10;\n" +
                "}";
        JavaCodeSnipParser parser = new JavaCodeSnipParser (code);
        parser.parse ();


        Matcher m = parser.classPattern.matcher ("public class VirtualConstruction extends VirtualMethod {");
        if (m.find ()) {
            System.out.println ("found");
        } else {
            System.out.println ("not found");
        }
    }
*/
}